using System;
using System.Collections.Generic;
using System.Text;
using Spacedash.Logic.Scenario.Cells;
using Spacedash.Logic.Scenario;
using Barrage.Global;
using Spacedash.Logic.RaceStates;

namespace Spacedash.Logic
{
    /// <summary>
    /// Structure that holds race creation parameters, such as scenario name or player number
    /// </summary>
    public struct RaceCreationParams
    {
        /// <summary>
        /// Scenario name
        /// </summary>
        public string ScenarioName;

        /// <summary>
        /// Player number (from 1 to 4)
        /// </summary>
        public int PlayerNumber;

        /// <summary>
        /// Number of laps of the race
        /// </summary>
        public int LapNumber;

        Profile[] playerProfiles;

        /// <summary>
        /// Constructor. Inits the structure with the specified data
        /// </summary>
        /// <param name="scenarioName">Scenario name</param>
        /// <param name="playerNumber">Player number</param>
        /// <param name="lapNumber">Lap number</param>
        public RaceCreationParams(string scenarioName, int playerNumber, int lapNumber)
        {
            this.ScenarioName = scenarioName;
            this.PlayerNumber = playerNumber;
            this.LapNumber = lapNumber;
            playerProfiles = new Profile[playerNumber];
        }
        /// <summary>
        /// Sets the selected profile of the specified player
        /// </summary>
        /// <param name="index">Player index</param>
        /// <param name="p">Profile that the player will use</param>
        public void setProfile(int index, Profile p)
        {
            playerProfiles[index] = p;
        }

        /// <summary>
        /// Gets the selected profile of the specified player
        /// </summary>
        /// <param name="index">Player index</param>
        /// <returns>Profile that the player will use</returns>
        public Profile getProfile(int index)
        {
            return playerProfiles[index];
        }
    }

    /// <summary>
    /// Inits and processes all of the logic in a SpaceDash race
    /// </summary>
    public class Race
    {
        /// <summary>
        /// Name of the pattern file loaded to add patterns to cellmanager
        /// </summary>
        public const string PATTERN_FILE = "Patterns.xml";
        /// <summary>
        /// Name of the directory that stores pattern data
        /// </summary>
        public const string PATTERNS_DIR = "Patterns/";
        
        RaceState state;
        /// <summary>
        /// Current state of the race
        /// </summary>
        public RaceState State { get { return state; } set { state = value; } }

        Spacedash.Logic.Scenario.Scenario scenario;
        /// <summary>
        /// Race scenario
        /// </summary>
        public Spacedash.Logic.Scenario.Scenario Scenario { get { return scenario; } }

        int playerNumber;
        /// <summary>
        /// Number of players in the race
        /// </summary>
        public int PlayerNumber { get { return playerNumber; } }

        int lapNumber;
        /// <summary>
        /// Length of the race in laps
        /// </summary>
        public int LapNumber { get { return lapNumber; } }

         List<Ship> finishedShips;
         SortedList<int,Ship> orderedShips;
        /// <summary>
        /// Returns a list of ships ordered by its current place in the race instead of by player index
        /// </summary>
        public SortedList<int, Ship> OrderedShips { get { return orderedShips; } }
         List<Ship> ships;
        /// <summary>
        /// Returns the list of players sorted by player index
        /// </summary>
        public List<Ship> Ships { get { return ships; } }
        /// <summary>
        /// Constructor. Inits the race.
        /// </summary>
        /// <param name="rcp">Race Creation Parameters</param>
        public Race(RaceCreationParams rcp)
        {
            CellManager.ClearPatterns();
            CellManager.LoadPatterns(PATTERNS_DIR+PATTERN_FILE);
            scenario = BitmapScenarioLoader.LoadScenario(Spacedash.Logic.Scenario.Scenario.SCENARIO_DIR + rcp.ScenarioName + Spacedash.Logic.Scenario.Scenario.SCENARIO_EXT);
            ships = new List<Ship>(rcp.PlayerNumber);
            orderedShips = new SortedList<int, Ship>(rcp.PlayerNumber);
            finishedShips = new List<Ship>(rcp.PlayerNumber);
            this.playerNumber = rcp.PlayerNumber;
            this.lapNumber = rcp.LapNumber;
            for (int i = 0; i < rcp.PlayerNumber; i++)
            {
                Ship s = new Ship(scenario,i,rcp.getProfile(i));
                s.ScenarioPosition = new SlimDX.Vector2(i - 2, 0);
                ships.Add(s);                
            }
            state = new LoadingRaceState(this);
        }

        /// <summary>
        /// Updates the race logic (State and Ships)
        /// </summary>
        public void Update()
        {
            state.Update();
            foreach(Ship s in ships)
                s.Update();
        }

        /// <summary>
        /// Sets the specified ship as finished
        /// </summary>
        /// <param name="s">Ship that has finished the race</param>
        /// <returns>Ship's final position (Zero-based)</returns>
        public int AddFinishedShip(Ship s)
        {
            int pos = finishedShips.Count;
            finishedShips.Add(s);
            return pos;
        }

        /// <summary>
        /// Sorts the orderedShips array based on each ship's position in the race
        /// </summary>
        public void OrderShips()
        {
            orderedShips.Clear();
            foreach(Ship ship in ships)
            {
                if (!orderedShips.ContainsKey(ship.RacePosition))
                    orderedShips.Add(ship.RacePosition,ship);
            }
        }
    }
}
